﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using System.Reflection;

namespace SharpHomeEngine
{
    public class Device
    {
        protected string MyName;
        protected string MyTypeName = "BaseDevice";
        internal DeviceInterface DeviceInterface;
        
        public string Name { get { return MyName; } } //the name of the instance. IE "bedroom 1 light switch"
        public string TypeName { get { return TypeName; } } //the name of the type of device. IE "Insteon Light Switch"
        public string Address
        {
            get
            {
                return GetDeviceAddress(DeviceInterface, this);
            }
        }

        protected void RaiseDeviceEvent(String Event, Tag Tag, object Value){
            if (this.DeviceInterface != null)
            {
                if (this.DeviceInterface.StateEngine != null)
                {
                    this.DeviceInterface.StateEngine.RaiseDeviceEvent(this, Event, Tag, Value);
                }
            }
        }

        public Device(DeviceInterface DeviceInterface, string Name)
        {
            CheckName(Name);
            if (DeviceInterface == null)
            {
                throw new Exception("Device Interface cannot be null");
            }
            this.DeviceInterface = DeviceInterface;
            MyName = Name;
        }

        public static string GetDeviceAddress(DeviceInterface DeviceInterface, Device Device)
        {
            return GetDeviceAddress(DeviceInterface.Name, Device.Name);
        }

        public static String GetDeviceAddress(String DeviceInterface, String Device)
        {
            return DeviceInterface + "." + Device;
        }

        protected void CheckName(String Name)
        {
            if (Name == null)
            {
                throw new Exception("Name cannot be null");
            }
            if (Name.Length == 0)
            {
                throw new Exception("Name cannot be empty");
            }
            Regex X = new Regex(@"^[\w]*$");
            if (!X.IsMatch(Name))
            {
                throw new Exception("A tag name can only consist of letters, numbers, and the underscore character!");
            }
        }

        /// <summary>
        /// Uses reflection to get the tags in the device
        /// </summary>
        /// <returns></returns>
        internal virtual List<Tag> GetTags()
        {
            List<Tag> Tags = new List<Tag>();
            Type Type = this.GetType();

            FieldInfo[] Fields = Type.GetFields(BindingFlags.Instance | BindingFlags.NonPublic);

            foreach (FieldInfo Field in Fields)
            {
                if (Field.FieldType.IsSubclassOf(typeof(Tag)))
                {
                    Tag Tag = (Tag)Field.GetValue(this);
                    Tags.Add(Tag);
                }
            }

            PropertyInfo[] Properties = Type.GetProperties(BindingFlags.Instance | BindingFlags.NonPublic);
            foreach (PropertyInfo Property in Properties)
            {
                if (Property.PropertyType.IsSubclassOf(typeof(Tag)))
                {
                    Tag Tag = (Tag)Property.GetValue(this, null);
                    Tags.Add(Tag);
                }
            }
            return Tags;
        }
    }
}
